// Copyright (c) 2009 Alistair Jones
// This program is made available under the terms of the MIT License.
package org.hypirinha.html.codegen;

import static org.hypirinha.html.codegen.CodegenUtil.capitalise;

import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

public class Element {

    private String name;
    private SortedSet<String> contentElementTypes = new TreeSet<String>();
    private SortedSet<String> containingElementTypes = new TreeSet<String>();

    public Element(String name) {
        this.name = name;
    }

    public void addContentElementTypes(Set<String> contentElementTypes) {
        this.contentElementTypes.addAll(contentElementTypes);
    }

    public void addContainingElementType(String containingElementType) {
        containingElementTypes.add(containingElementType);
    }
    
    public GeneratedInterface createElementInterface() {
        GeneratedInterface generatedInterface = new GeneratedInterface("org.hypirinha.html.elements",
                capitalise(name));
        generatedInterface.addImport("org.hypirinha.html.elements.contents.*");
        generatedInterface.addImport("org.hypirinha.html.attributes.AnyAttribute");
        generatedInterface.addImport("org.hypirinha.html.Text");

        if (contentElementTypes.contains("object")) {
            generatedInterface.addImport("org.hypirinha.html.elements.Object");
        }

        generatedInterface.addBaseInterface("Contains<" + capitalise(name) + ", " + capitalise(name) + "Content>");
        for (String containingElementType : containingElementTypes) {
            generatedInterface.addBaseInterface(capitalise(containingElementType) + "Content");
        }

        InnerInterface attributeInterface = new InnerInterface("Attribute");
        attributeInterface.addBaseInterface("AnyAttribute");
        generatedInterface.getMembers().add(attributeInterface);

        for (String elementType : contentElementTypes) {
            String elementClass = capitalise(elementType);
            generatedInterface.getMembers().add(new AbstractMethod(elementType, elementClass, elementClass + ".Attribute... attributes"));
        }

        generatedInterface.getMembers().add(new AbstractMethod("text", "Text", "String content"));
        return generatedInterface;
    }


    public GeneratedInterface createContentInterface() {
        GeneratedInterface generatedInterface = new GeneratedInterface("org.hypirinha.html.elements.contents", capitalise(name) + "Content");
        generatedInterface.addImport("org.hypirinha.html.Content");
        generatedInterface.addBaseInterface("Content");
        return generatedInterface;
    }

    public GeneratedClass createElementImplementation() {
        GeneratedClass generatedClass = new GeneratedClass("org.hypirinha.html.elements.implementations", capitalise(name) + "Element");
        generatedClass.addImport("org.hypirinha.html.elements.*");
        generatedClass.addImport("org.hypirinha.html.elements.contents.*");
        generatedClass.addImport("org.hypirinha.html.Text");

        if (name.equals("object") || contentElementTypes.contains("object")) {
            generatedClass.addImport("org.hypirinha.html.elements.Object");
        }

        generatedClass.addInterface(capitalise(name));
        generatedClass.setSuperClass("Element<" + capitalise(name) + ", " + capitalise(name) + "Content>");
        for (String containingElementType : containingElementTypes) {
            generatedClass.addInterface(capitalise(containingElementType) + "Content");
        }
        generatedClass.getMembers().add(new Constructor(capitalise(name) + "Element",
                capitalise(name) + ".Attribute... attributes",
                "super(\"" + name + "\", attributes);"));
        for (String elementType : contentElementTypes) {
            String elementClass = capitalise(elementType);
            generatedClass.getMembers().add(
                    new ConcreteMethod(elementType, elementClass,
                            elementClass + ".Attribute... attributes",
                            "return newChild(new " + capitalise(elementType) + "Element(attributes));"));
        }
        generatedClass.getMembers().add(new ConcreteMethod("text", "Text", "String content", "return newChild(new Text(content));"));

        return generatedClass;
    }
}